/*****************************************************************************
*
*  PROJECT:     Native Executive
*  LICENSE:     See LICENSE in the top level directory
*  FILE:        NativeExecutive/CExecutiveManager.rwlock.internal.h
*  PURPOSE:     Read/Write lock internal implementation header
*  DEVELOPERS:  Martin Turski <quiret@gmx.de>
*
*  Multi Theft Auto is available from http://www.multitheftauto.com/
*
*****************************************************************************/

#ifndef _NATIVE_EXECUTIVE_READ_WRITE_LOCK_INTERNAL_
#define _NATIVE_EXECUTIVE_READ_WRITE_LOCK_INTERNAL_

// We assume that the Windows headers have been included already.

#include <atomic>
#include <condition_variable>
#include <thread>
#include <shared_mutex>

#include <PluginHelpers.h>

BEGIN_NATIVE_EXECUTIVE

// Lock implementation anonymous functions.
struct readWriteLockEnv_t;

typedef void (*rwlockimpl_construct)( void *lockmem, readWriteLockEnv_t *lockEnv );
typedef void (*rwlockimpl_destroy)( void *lockmem, readWriteLockEnv_t *lockEnv );
typedef void (__thiscall*rwlockimpl_enter_read)( void *lockmem, readWriteLockEnv_t *lockEnv );
typedef void (__thiscall*rwlockimpl_leave_read)( void *lockmem, readWriteLockEnv_t *lockEnv );
typedef void (__thiscall*rwlockimpl_enter_write)( void *lockmem, readWriteLockEnv_t *lockEnv );
typedef void (__thiscall*rwlockimpl_leave_write)( void *lockmem, readWriteLockEnv_t *lockEnv );
typedef bool (__thiscall*rwlockimpl_try_enter_read)( void *lockmem, readWriteLockEnv_t *lockEnv );
typedef bool (__thiscall*rwlockimpl_try_enter_write)( void *lockmem, readWriteLockEnv_t *lockEnv );

class CExecutiveManagerNative;

// ReadWrite lock environment.
struct readWriteLockEnv_t
{
    // Decide about the locking implementation.
    void Initialize( CExecutiveManagerNative *execMan );
    void Shutdown( CExecutiveManagerNative *execMan );

    // Things to be used.
    // Native things.
#define METHODDECL_GLOBAL( funcName ) \
    typedef decltype( &##funcName ) funcName##_t; \
    funcName##_t funcName = NULL;
#define METHODDECL_FETCH( module, funcName ) \
    this->##funcName = (funcName##_t)GetProcAddress( module, #funcName );

    HMODULE kernel32_module;

    METHODDECL_GLOBAL( InitializeSRWLock );
    METHODDECL_GLOBAL( AcquireSRWLockShared );
    METHODDECL_GLOBAL( ReleaseSRWLockShared );
    METHODDECL_GLOBAL( AcquireSRWLockExclusive );
    METHODDECL_GLOBAL( ReleaseSRWLockExclusive );
    METHODDECL_GLOBAL( TryAcquireSRWLockShared );
    METHODDECL_GLOBAL( TryAcquireSRWLockExclusive );

    // Normal Read Write Lock.
    size_t readWriteLockSize = 0;
    rwlockimpl_construct        constructor = NULL;
    rwlockimpl_destroy          destructor = NULL;
    rwlockimpl_enter_read       enter_read = NULL;
    rwlockimpl_leave_read       leave_read = NULL;
    rwlockimpl_enter_write      enter_write = NULL;
    rwlockimpl_leave_write      leave_write = NULL;
    rwlockimpl_try_enter_read   try_enter_read = NULL;
    rwlockimpl_try_enter_write  try_enter_write = NULL;

    // Reentrant Read Write Lock.
    size_t rentReadWriteLockSize = 0;
    rwlockimpl_construct        rent_constructor = NULL;
    rwlockimpl_destroy          rent_destructor = NULL;
    rwlockimpl_enter_read       rent_enter_read = NULL;
    rwlockimpl_leave_read       rent_leave_read = NULL;
    rwlockimpl_enter_write      rent_enter_write = NULL;
    rwlockimpl_leave_write      rent_leave_write = NULL;
    rwlockimpl_try_enter_read   rent_try_enter_read = NULL;
    rwlockimpl_try_enter_write  rent_try_enter_write = NULL;
};

END_NATIVE_EXECUTIVE

#endif //_NATIVE_EXECUTIVE_READ_WRITE_LOCK_INTERNAL_